/*
* "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $"
*
* Attribute support code for Mini-XML, a small XML-like file parsing library.
*
* Copyright 2003-2010 by Michael R Sweet.
*
* These coded instructions, statements, and computer programs are the
* property of Michael R Sweet and are protected by Federal copyright
* law.  Distribution and use rights are outlined in the file "COPYING"
* which should have been included with this file.  If this file is
* missing or damaged, see the license at:
*
*     http://www.minixml.org/
*
* Contents:
*
*   mxmlElementDeleteAttr() - Delete an attribute.
*   mxmlElementGetAttr()    - Get an attribute.
*   mxmlElementSetAttr()    - Set an attribute.
*   mxmlElementSetAttrf()   - Set an attribute with a formatted value.
*   mxml_set_attr()         - Set or add an attribute name/value pair.
*/

/*
* Include necessary headers...
*/

#include "mxml-config.h"
#include "mxml.h"


/*
* Local functions...
*/

static int	mxml_set_attr(mxml_node_t *node, const char *name,
	char *value);


/*
* 'mxmlElementDeleteAttr()' - Delete an attribute.
*
* @since Mini-XML 2.4@
*/

void
	mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
	const char  *name)/* I - Attribute name */
{
	int		i;			/* Looping var */
	mxml_attr_t	*attr;			/* Cirrent attribute */


#ifdef DEBUG
	fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
		node, name ? name : "(null)");
#endif /* DEBUG */

	/*
	* Range check input...
	*/

	if (!node || node->type != MXML_ELEMENT || !name)
		return;

	/*
	* Look for the attribute...
	*/

	for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
		i > 0;
		i --, attr ++)
	{
#ifdef DEBUG
		printf("    %s=\"%s\"\n", attr->name, attr->value);
#endif /* DEBUG */

		if (!strcmp(attr->name, name))
		{
			/*
			* Delete this attribute...
			*/

			free(attr->name);
			free(attr->value);

			i --;
			if (i > 0)
				memmove(attr, attr + 1, i * sizeof(mxml_attr_t));

			node->value.element.num_attrs --;
			return;
		}
	}
}


/*
* 'mxmlElementGetAttr()' - Get an attribute.
*
* This function returns NULL if the node is not an element or the
* named attribute does not exist.
*/

const char *				/* O - Attribute value or NULL */
	mxmlElementGetAttr(mxml_node_t *node,	/* I - Element node */
	const char  *name)	/* I - Name of attribute */
{
	int		i;			/* Looping var */
	mxml_attr_t	*attr;			/* Cirrent attribute */


#ifdef DEBUG
	fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
		node, name ? name : "(null)");
#endif /* DEBUG */

	/*
	* Range check input...
	*/

	if (!node || node->type != MXML_ELEMENT || !name)
		return (NULL);

	/*
	* Look for the attribute...
	*/

	for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
		i > 0;
		i --, attr ++)
	{
#ifdef DEBUG
		printf("    %s=\"%s\"\n", attr->name, attr->value);
#endif /* DEBUG */

		if (!strcmp(attr->name, name))
		{
#ifdef DEBUG
			printf("    Returning \"%s\"!\n", attr->value);
#endif /* DEBUG */
			return (attr->value);
		}
	}

	/*
	* Didn't find attribute, so return NULL...
	*/

#ifdef DEBUG
	puts("    Returning NULL!\n");
#endif /* DEBUG */

	return (NULL);
}


/*
* 'mxmlElementSetAttr()' - Set an attribute.
*
* If the named attribute already exists, the value of the attribute
* is replaced by the new string value. The string value is copied
* into the element node. This function does nothing if the node is
* not an element.
*/

void
	mxmlElementSetAttr(mxml_node_t *node,	/* I - Element node */
	const char  *name,	/* I - Name of attribute */
	const char  *value)	/* I - Attribute value */
{
	char	*valuec;			/* Copy of value */


#ifdef DEBUG
	fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
		node, name ? name : "(null)", value ? value : "(null)");
#endif /* DEBUG */

	/*
	* Range check input...
	*/

	if (!node || node->type != MXML_ELEMENT || !name)
		return;

	if (value)
		valuec = strdup(value);
	else
		valuec = NULL;

	if (mxml_set_attr(node, name, valuec))
		free(valuec);
}


/*
* 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
*
* If the named attribute already exists, the value of the attribute
* is replaced by the new formatted string. The formatted string value is
* copied into the element node. This function does nothing if the node
* is not an element.
*
* @since Mini-XML 2.3@
*/

void
	mxmlElementSetAttrf(mxml_node_t *node,	/* I - Element node */
	const char  *name,	/* I - Name of attribute */
	const char  *format,/* I - Printf-style attribute value */
	...)		/* I - Additional arguments as needed */
{
	va_list	ap;			/* Argument pointer */
	char		*value;			/* Value */


#ifdef DEBUG
	fprintf(stderr,
		"mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
		node, name ? name : "(null)", format ? format : "(null)");
#endif /* DEBUG */

	/*
	* Range check input...
	*/

	if (!node || node->type != MXML_ELEMENT || !name || !format)
		return;

	/*
	* Format the value...
	*/

	va_start(ap, format);
	value = _mxml_vstrdupf(format, ap);
	va_end(ap);

	if (!value)
		mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
		name, node->value.element.name);
	else if (mxml_set_attr(node, name, value))
		free(value);
}


/*
* 'mxml_set_attr()' - Set or add an attribute name/value pair.
*/

static int				/* O - 0 on success, -1 on failure */
	mxml_set_attr(mxml_node_t *node,	/* I - Element node */
	const char  *name,	/* I - Attribute name */
	char        *value)	/* I - Attribute value */
{
	int		i;			/* Looping var */
	mxml_attr_t	*attr;			/* New attribute */


	/*
	* Look for the attribute...
	*/

	for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
		i > 0;
		i --, attr ++)
		if (!strcmp(attr->name, name))
		{
			/*
			* Free the old value as needed...
			*/

			if (attr->value)
				free(attr->value);

			attr->value = value;

			return (0);
		}

		/*
		* Add a new attribute...
		*/

		if (node->value.element.num_attrs == 0)
			attr = malloc(sizeof(mxml_attr_t));
		else
			attr = realloc(node->value.element.attrs,
			(node->value.element.num_attrs + 1) * sizeof(mxml_attr_t));

		if (!attr)
		{
			mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
				name, node->value.element.name);
			return (-1);
		}

		node->value.element.attrs = attr;
		attr += node->value.element.num_attrs;

		if ((attr->name = strdup(name)) == NULL)
		{
			mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
				name, node->value.element.name);
			return (-1);
		}

		attr->value = value;

		node->value.element.num_attrs ++;

		return (0);
}


/*
* End of "$Id: mxml-attr.c 408 2010-09-19 05:26:46Z mike $".
*/
